home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programmer Power Tools
/
Programmer Power Tools.iso
/
asmutl
/
conv_a11.arc
/
POSBM2.ASM
< prev
next >
Wrap
Assembly Source File
|
1989-11-06
|
6KB
|
209 lines
;Faster string search routine to substitute the POS()
;function in Turbo Pascal 4 or 5.
;Based on the Boyer-Moore algorithm.
;Program Author: Costas Menico (Dr Dobbs, Jul 89)
;
;Declare as follows:
; {$F+}
; {$L SEARCH.OBJ}
; FUNCTION posBM(pat,str : STRING) : BYTE; EXTERNAL;
;Call as follows:
; location := posBM(pat, str);
;
;Courtesy of Toad Hall
;v1.2 Toad Hall, 5 Nov 89
; Tightening up a little more
;v1.1 Toad Hall Tweaks, 11 Jun 89
; - Very minor, no functional changes
SKIPARRLENGTH EQU 256 ;length of the skip array
;function work stack
dstk STRUC
patlen DW ? ;pattern length (also BP base work area)
strlen DW ? ;str length
skiparr DB SKIPARRLENGTH DUP(?) ;skip array
;v1.2 We aren't saving pattern and string text addresses any more,
; instead using them directly from the function parameters
;pattxt DD 0 ;pattern address
;strtxt DD 0 ;string text address
dstk ENDS
;Total stack (caller's plus work stack)
cstk STRUC
ourdata DB SIZE dstk DUP(?) ;work stack size
bpsave DW 0 ;save BP here
retaddr DD 0 ;points to return address
straddr DD 0 ;points to string address
pataddr DD 0 ;points to pattern address
cstk ENDS
PARAMSIZE EQU SIZE pataddr + SIZE straddr ;size ofr parameter list
PUBLIC PosBM ;function name declaration
CODE SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:CODE
;Entry point to POSBM function
PosBM PROC FAR
push bp
sub sp,SIZE dstk ;create work area
mov bp,sp
push DS ;save caller's DS
xor ah,ah ;clear MSB
cld
;Get and save pattern length and address
lds si,[bp.pataddr]
;v1.2 mov WORD PTR [bp.pattxt][2],DS
lodsb ;get pattern length (1 byte)
or al,al ;if length is null
jnz NotNullP
jmp NoMatch ; then exit
NotNullP:
mov cx,ax ;save pattern len to check if 1 later
mov [bp.patlen],ax ;save pattern length
;v1.2 mov WORD PTR [bp.pattxt],si ;save address
inc word ptr [bp.pataddr] ;bump pattern address v1.2
;Get and save string text length and address
lds si,[bp.straddr]
;v1.2 mov WORD PTR [bp.strtxt][2],DS
lodsb ;get string length
or al,al ;if string text is null
jnz NotNullS
jmp NoMatch ; then exit
NotNullS:
mov [bp.strlen],ax ;save string length
;v1.2 mov WORD PTR [bp.strtxt],si ;save address
inc word ptr [bp.straddr] ;bump string address by 1 v1.2
;v1.2 cmp cx,1 ;is pattern length 1 char?
cmp cl,1 ;is pattern length 1 char? v1.2
;(CH guaranteed 0) v1.2
jne Do_Boyer_Moore ;nope
;v1.2 lds si,[bp.pattxt] ;yes, do a straight search
lds si,[bp.pataddr] ;yes, do a straight search v1.2
mov cx,ax ;still has string length v1.1
lodsb ;get the single char pattern
;v1.2 les di,[bp.strtxt] ;get string address
les di,[bp.straddr] ;get string address v1.2
repne scasb ;search
jz Match1 ;found - adjust last DI psn
jmp NoMatch ;not found, exit
Match1:
mov si,di
dec si ;adjust SI psn v1.2
dec si ; by 2 v1.2
jmp ExactMatch
Do_Boyer_Moore:
;Fill the ASCII character skiparray with the pattern length
lea di,[bp.skiparr] ;get skip array address
mov dx,SS
mov ES,dx
mov al,BYTE PTR [bp.patlen] ;get pattern size
mov ah,al ;put in AH also
mov cx,SKIPARRLENGTH / 2 ;array size
rep stosw ;fill with pattern length
;Replace in the ASCII skiparray the corresponding
;character offset from the end of the pattern minus 1
;v1.2 lds si,[bp.pattxt] ;get pattern address
lds si,[bp.pataddr] ;get pattern address v1.2
xor ah,ah ;clear MSB v1.1
mov cx,ax ;AX is still pattern length v1.1
dec cx ; minus 1
mov bx,bp ;save BP
lea bp,[bp.skiparr] ;get skip array address
Fill_SkipArray:
lodsb ;get char from pattern
mov di,ax ;use it as an index
mov [bp+di],cl ;store the last skip value
loop Fill_SkipArray
lodsb
mov di,ax
mov [bp+di],cl ;store the last skip value
mov bp,bx ;restore BP
;Now initialize our pattern and string text pointers
;to start searching
;v1.2 lds si,[bp.strtxt] ;string address
lds si,[bp.straddr] ;string address v1.2
lea di,[bp.skiparr] ;skip array address
mov dx,[bp.strlen] ;string length
dec dx ; minus 1 for each check
mov ax,[bp.patlen] ;pattern length
dec ax ; starting skip value
xor bh,bh ;clear MSB
std ;reverse compare
;Get char from text. Use the char as an index
;into the skip array, looking for a skip value of 0.
;If found, execute a brute force search on the pattern.
SearchLast:
sub dx,ax ;check if string exhausted
jc NoMatch ;yes, no match
add si,ax ;no - slide pattern with skip value
mov bl,[si] ;get char, use as an index
mov al,SS:[di+bx] ; and get the new skip value
or al,al ;if 0, then possible match
jne SearchLast ; try again by sliding to right
;We have a possible match,
;therefore do the reverse Brute-force compare
mov bx,si ;save string addr
mov cx,[bp.patlen] ;pattern length
;v1.2 les di,[bp.pattxt] ;pattern address
les di,[bp.pataddr] ;pattern address v1.2
dec di ;adjust
add di,cx ; and add to point to EOS
repe cmpsb ;do reverse compare
je ExactMatch ;if equal, we found a match
mov ax,1 ;else set skip value to 1
lea di,[bp.skiparr] ;skip array address
mov si,bx ;get string address
xor bh,bh ;No - clear MSB
jmp SHORT SearchLast ;try again
ExactMatch:
mov ax,si ;save current psn in string
;v1.2 lds si,[bp.strtxt] ;get start of strtxt
lds si,[bp.straddr] ;get start of string text v1.2
sub ax,si ;sub and add 2 to get psn
inc ax ; in string text v1.2
inc ax ; where pattern is found v1.2
jmp SHORT EndSearch ;exit function
NoMatch:
xor ax,ax ;no match, return a 0
EndSearch:
cld
pop DS ;recover
mov sp,bp ;recover last stack psn
add sp,SIZE dstk ;clear up work area
pop bp ;recover BP
ret PARAMSIZE ;return with AX the POSBM value
PosBM ENDP
CODE ENDS
END